/*
 * MIT License
 *
 * Copyright (c) 2024-2025 milkpotatoes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#undef unix

#include <ark_native_engine.h>
#include <ecmascript/js_runtime_options.h>
#include <native_engine/native_create_env.h>

#include "napi_runner/napi_runner.h"

#include "napi_runner/arkruntime_utils.h"

static panda::ecmascript::JSRuntimeOptions g_runtimeOptions;
std::mutex ArkRuntimeUtils::g_arkRuntimeMapMutex;
std::unordered_map<pid_t, NapiRunner *> ArkRuntimeUtils::g_arkRuntimeMap;

void ArkRuntimeUtils::Init()
{
    NativeCreateEnv::RegCreateNapiEnvCallback(Create);
    NativeCreateEnv::RegDestroyNapiEnvCallback(Destory);
}

panda::ecmascript::JSRuntimeOptions *ArkRuntimeUtils::GetRuntimeOptions()
{
    return &g_runtimeOptions;
}

void ArkRuntimeUtils::SetJITState(bool enable)
{
    GetRuntimeOptions()->SetEnableJIT(enable);
}

bool ArkRuntimeUtils::ParseOptions(int argc, const char **argv)
{
    return GetRuntimeOptions()->ParseCommand(argc, argv);
}

std::string_view ArkRuntimeUtils::GetRuntimeHelpMessage()
{
    return panda::ecmascript::HELP_OPTION_MSG;
}

napi_status ArkRuntimeUtils::Create(napi_env *env)
{
    std::lock_guard<std::mutex> lock(g_arkRuntimeMapMutex);
    thread_local pid_t tid = gettid();
    if (g_arkRuntimeMap.find(tid) != g_arkRuntimeMap.end())
    {
        return napi_create_ark_runtime_only_one_env_per_thread;
    }
    NapiRunner *runner = new NapiRunner(&g_runtimeOptions);
    if (runner == nullptr)
    {
        return napi_generic_failure;
    }
    ArkNativeEngine *engine = const_cast<ArkNativeEngine *>(runner->GetEngine());
    auto vm = runner->GetVM();
    engine->SetCleanEnv([vm]() { JSNApi::DestroyJSVM(vm); });
    g_arkRuntimeMap.insert({tid, runner});
    *env = reinterpret_cast<napi_env>(engine);
    return napi_ok;
}

napi_status ArkRuntimeUtils::Destory(napi_env *env)
{
    std::lock_guard<std::mutex> lock(g_arkRuntimeMapMutex);
    for (auto [tid, runner] : g_arkRuntimeMap)
    {
        if (runner->GetEnv() == *env)
        {
            delete runner;
            g_arkRuntimeMap.erase(tid);
            *env = nullptr;
            return napi_ok;
        }
    }
    return napi_destroy_ark_runtime_env_not_exist;
}
